package com.mcxx.modules.miniSalvation.fundpay.service.write;

import com.google.common.collect.Lists;
import com.mcxx.common.exception.BizException;
import com.mcxx.modules.base.utils.excel.ImportExcel;
import com.mcxx.modules.miniSalvation.fundpay.dao.write.FundPayFamilyWriteDao;
import com.mcxx.modules.miniSalvation.fundpay.dao.write.FundPayMemberWriteDao;
import com.mcxx.modules.miniSalvation.fundpay.dto.AllowanceFundPayDTO;
import com.mcxx.modules.miniSalvation.fundpay.dto.CustomFundPayDTO;
import com.mcxx.modules.miniSalvation.fundpay.dto.FundPayFamilyDTO;
import com.mcxx.modules.miniSalvation.fundpay.dto.FuneralFundPayDTO;
import com.mcxx.modules.miniSalvation.fundpay.entity.FundPayEntity;
import com.mcxx.modules.miniSalvation.fundpay.entity.FundPayFamilyEntity;
import com.mcxx.modules.miniSalvation.fundpay.entity.FundPayMemberEntity;
import com.mcxx.modules.miniSalvation.fundpay.service.read.FundPayFamilyReadService;
import com.mcxx.modules.miniSalvation.fundpay.service.read.FundPayMemberReadService;
import com.mcxx.util.CommonUtil;
import com.mcxx.util.Constant;
import com.mcxx.util.DateUtil;
import com.yinhai.ta404.core.security.vo.UserAccountVo;
import com.yinhai.ta404.core.transaction.annotation.TaTransactional;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
@TaTransactional
public class FundPayMemberWriteService {

    @Autowired
    private FundPayMemberWriteDao fundPayMemberWriteDao;
    @Autowired
    private FundPayFamilyWriteDao fundPayFamilyWriteDao;
    @Autowired
    private FundPayFamilyWriteService fundPayFamilyWriteService;
    @Autowired
    private FundPayMemberReadService fundPayMemberReadService;
    @Autowired
    private FundPayFamilyReadService fundPayFamilyReadService;



    public int inserts(List<FundPayMemberEntity> fundPayMemberList){
        return fundPayMemberWriteDao.inserts(fundPayMemberList);
    }


    public void updateIgnoreNull(FundPayMemberEntity fundPayMemberEntity){
        int rst = fundPayMemberWriteDao.updateIgnoreNull(fundPayMemberEntity);
        if(rst <= 0){
            throw new BizException("-1", "修改成员信息异常");
        }
    }


    public int deleteByFundPayIds(List<String> fundPayIdList){
        return fundPayMemberWriteDao.deleteByFundPayIds(fundPayIdList);
    }


    public void deleteFundPayMember(String fundPayId, List<String> familyIdList){
        int rst = fundPayMemberWriteDao.deleteByFundPayIdAndFamilyId(fundPayId, familyIdList);
        if(rst <= 0){
            throw new BizException("-1", "保障金名册删除成员失败");
        }
    }





    public void delFamilyMemberForByDelMember(String fundPayId, List<String> memberIdList){

        fundPayMemberWriteDao.deleteByFundPayIdAndMemberId(fundPayId, memberIdList);


        fundPayFamilyWriteService.deleteFamilyByDelMember(fundPayId, memberIdList);


        fundPayFamilyWriteService.updateFamilyNumAndFundNumber(fundPayId, null);
    }


    public void addMemberForAllowance(FundPayEntity fundPayEntity, List<String> orderIdList, List<String> memberIdList){

        List<FundPayMemberEntity> fundPayMemberList = fundPayMemberReadService.getMemberByAllowanceAddMember(orderIdList, memberIdList);


        List<String> familyIdList = fundPayMemberList.stream().map(FundPayMemberEntity::getFamilyId).collect(Collectors.toList());


        List<FundPayFamilyEntity> fundPayFamilyList = fundPayFamilyReadService.getFamilyByAddAllowanceMember(fundPayEntity.getId(), orderIdList, familyIdList, fundPayEntity.getBusinessType());


        List<String> insertFamilyIdList = fundPayFamilyList.stream().map(FundPayFamilyEntity::getFamilyId).collect(Collectors.toList());


        List<String> updateFamilyIdList = familyIdList.stream().filter(familyId->!insertFamilyIdList.contains(familyId)).collect(Collectors.toList());


        AllowanceFundPayDTO allowanceFundPayDTO = new AllowanceFundPayDTO();
        BeanUtils.copyProperties(fundPayEntity, allowanceFundPayDTO);


        fundPayFamilyWriteService.calcGrantStandardByMember(fundPayFamilyList, fundPayMemberList, allowanceFundPayDTO);


        fundPayFamilyWriteService.insertFamilyMember(fundPayFamilyList, fundPayMemberList);


        fundPayFamilyWriteService.updateFamilyNumAndFundNumber(fundPayEntity.getId(), updateFamilyIdList);
    }







    public void updateRemark(String fundPayMemberId, String remark){
        FundPayMemberEntity fundPayMemberEntity = new FundPayMemberEntity();
        fundPayMemberEntity.setId(fundPayMemberId);
        fundPayMemberEntity.setRemark(remark);
        this.updateIgnoreNull(fundPayMemberEntity);
    }


    public void updateFundNumber(String fundPayMemberId, double fundNumber){
        FundPayMemberEntity fundPayMemberEntity = new FundPayMemberEntity();
        fundPayMemberEntity.setId(fundPayMemberId);
        fundPayMemberEntity.setFundNumber(fundNumber);
        this.updateIgnoreNull(fundPayMemberEntity);
    }


    public void updateMemberFundNumber(String fundPayFamilyId, double fundNumber){

        List<String> fundPayMemberIdList = fundPayMemberReadService.getIdByFundPayFamilyId(fundPayFamilyId);


        double remainder = fundNumber % fundPayMemberIdList.size();
        double average = (fundNumber - remainder) /  fundPayMemberIdList.size();

        for(int i = 0; i < fundPayMemberIdList.size(); i++){
            FundPayMemberEntity fundPayMemberEntity = new FundPayMemberEntity();
            fundPayMemberEntity.setId(fundPayMemberIdList.get(i));

            if (i == 0) {
                fundPayMemberEntity.setFundNumber(average + remainder);
            }else{
                fundPayMemberEntity.setFundNumber(average);
            }
            this.updateIgnoreNull(fundPayMemberEntity);
        }
    }


    public void addMemberForCustom(FundPayEntity fundPayEntity, List<String> orderIdList, List<String> memberIdList){

        List<FundPayMemberEntity> fundPayMemberList = fundPayMemberReadService.getMemberByAllowanceAddMember(orderIdList, memberIdList);


        List<String> familyIdList = fundPayMemberList.stream().map(FundPayMemberEntity::getFamilyId).collect(Collectors.toList());


        List<FundPayFamilyEntity> fundPayFamilyList = fundPayFamilyReadService.getFamilyByAddCustomMember(fundPayEntity.getId(), orderIdList, familyIdList, fundPayEntity.getBusinessType());


        Map<String, String> familyFundPayFamilyIdMap = fundPayFamilyList.stream()
                .filter(familyEntity -> !CommonUtil.invalidArgs(familyEntity.getFundPayFamilyId()))
                .collect(Collectors.toMap(c->c.getFamilyId(), c->c.getFundPayFamilyId()));


        List<FundPayFamilyEntity> insertFundPayFamilyList = fundPayFamilyList.stream()
                .filter(familyEntity -> CommonUtil.invalidArgs(familyEntity.getFundPayFamilyId()))
                .collect(Collectors.toList());


        CustomFundPayDTO customFundPayDTO = new CustomFundPayDTO();
        BeanUtils.copyProperties(fundPayEntity, customFundPayDTO);


        fundPayFamilyWriteService.calcCustomByMember(insertFundPayFamilyList, fundPayMemberList, customFundPayDTO, familyFundPayFamilyIdMap);


        fundPayFamilyWriteService.insertFamilyMember(insertFundPayFamilyList, fundPayMemberList);


        fundPayFamilyWriteService.updateFamilyNumAndFundNumber(fundPayEntity.getId(), new ArrayList<>(familyFundPayFamilyIdMap.keySet()));
    }







    public void addMemberForFuneral(FundPayEntity fundPayEntity, List<String> orderIdList, List<String> memberIdList){

        List<FundPayMemberEntity> fundPayMemberList = fundPayMemberReadService.getMemberByFuneralAddMember(orderIdList, memberIdList);


        List<String> familyIdList = fundPayMemberList.stream().map(FundPayMemberEntity::getFamilyId).collect(Collectors.toList());


        List<String> updateFamilyIdList = fundPayFamilyReadService.getFamilyId(fundPayEntity.getId());


        List<String> insertFamilyIdList = familyIdList.stream().filter(familyId->updateFamilyIdList.contains(familyId) == false).collect(Collectors.toList());


        FuneralFundPayDTO funeralFundPayDTO = new FuneralFundPayDTO();
        BeanUtils.copyProperties(fundPayEntity, funeralFundPayDTO);


        List<FundPayFamilyEntity> fundPayFamilyList = this.perfectFundPayInfo(fundPayMemberList, funeralFundPayDTO, insertFamilyIdList);


        fundPayFamilyWriteService.insertFamilyMember(fundPayFamilyList, fundPayMemberList);


        fundPayFamilyWriteService.updateFamilyNumAndFundNumber(fundPayEntity.getId(), updateFamilyIdList);
    }


    public List<FundPayFamilyEntity> perfectFundPayInfo(List<FundPayMemberEntity> fundPayMemberList,
                                                        FuneralFundPayDTO funeralFundPayDTO,
                                                        List<String> insertFamilyIdList){
        Date createDate = new Date();
        Map<String, FundPayFamilyEntity> fundPayFamilyMap = new HashMap<>();

        FundPayFamilyEntity tempFundPayFamilyEntity;

        for (FundPayMemberEntity memberEntity : fundPayMemberList){
            String familyId = memberEntity.getFamilyId();
            if(insertFamilyIdList.contains(familyId) && fundPayFamilyMap.containsKey(familyId)){
                tempFundPayFamilyEntity = fundPayFamilyMap.get(familyId);

                tempFundPayFamilyEntity.setPersonNumber(tempFundPayFamilyEntity.getPersonNumber() + 1);
                tempFundPayFamilyEntity.setFundNumber(tempFundPayFamilyEntity.getFundNumber() + memberEntity.getFundNumber());
            }else{
                tempFundPayFamilyEntity = new FundPayFamilyEntity();

                tempFundPayFamilyEntity.setOrderId(memberEntity.getOrderId());
                tempFundPayFamilyEntity.setFamilyId(familyId);
                tempFundPayFamilyEntity.setMemberId(memberEntity.getMasterMemberId());
                tempFundPayFamilyEntity.setPersonNumber(1);
                tempFundPayFamilyEntity.setFundNumber(memberEntity.getFundNumber());
                tempFundPayFamilyEntity.setAreaCode(memberEntity.getAreaCode());
                tempFundPayFamilyEntity.setCountyCode(memberEntity.getCountyCode());
                tempFundPayFamilyEntity.setStreetCode(memberEntity.getStreetCode());

                tempFundPayFamilyEntity.setId(Constant.getUUID());
                tempFundPayFamilyEntity.setFundPayId(funeralFundPayDTO.getId());

                tempFundPayFamilyEntity.setPayDate(funeralFundPayDTO.getPayDate());

                tempFundPayFamilyEntity.setCreateTime(createDate);
            }

            memberEntity.setId(Constant.getUUID());

            memberEntity.setFundPayId(funeralFundPayDTO.getId());

            memberEntity.setPayDate(funeralFundPayDTO.getPayDate());

            memberEntity.setCreateTime(createDate);

            memberEntity.setFundPayFamilyId(tempFundPayFamilyEntity.getId());

            fundPayFamilyMap.put(familyId, tempFundPayFamilyEntity);
        }

        return new ArrayList<>(fundPayFamilyMap.values());
    }



    public String importCustomFundPayObjects(String customFundPayId, MultipartFile file, UserAccountVo curUserAccount) {
        log.info("低保自定义导入》》》》》》》》》》》》》》》");

        Map<String, FundPayMemberEntity> excelMemberMap = ImportExcel.importExcelCustomFundPay(file);


        FundPayEntity customFundPayDTO = fundPayFamilyReadService.getCustomRollById(customFundPayId);
        if (null == customFundPayDTO) {
            throw new BizException("-1", "名册异常，无法导入数据");
        }



        List<String> idCardList = new ArrayList<>(excelMemberMap.keySet());

        List<FundPayMemberEntity> canAddMemberList = fundPayFamilyReadService.getCustomMemberListByIdcard(customFundPayDTO, idCardList, curUserAccount);
        if (canAddMemberList.size() == 0) {
            throw new BizException("-1", "没有可以导入到选中的补发名册的成员，或者选择的名册与导入对象的类型不匹配，请核对");
        }


        List<FundPayMemberEntity> rollMembers = fundPayMemberReadService.getByFundPayId(customFundPayId);


        for (FundPayMemberEntity obj : canAddMemberList) {
            FundPayMemberEntity memberEntity = excelMemberMap.get(obj.getIdcard());
            if (memberEntity == null) {
                throw new BizException("-1", "导入失败，身份证号【" + obj.getIdcard() + "】数据有误，请检查");
            }
            if (memberEntity.getPersonNumber() > 1) {
                throw new BizException("-1", "导入失败，暂不支持家庭信息导入，请按成员信息导入");
            }
            Double fundNumber = memberEntity.getFundNumber();
            obj.setFundNumber(fundNumber);
        }



        List<FundPayMemberEntity> sameList = canAddMemberList.stream()
                .filter(item -> rollMembers.stream().map(FundPayMemberEntity::getMemberId)
                        .collect(Collectors.toList()).contains(item.getMemberId()))
                .collect(Collectors.toList());

        Map<String, List<FundPayMemberEntity>> listMap = sameList.stream().collect(Collectors.groupingBy(FundPayMemberEntity::getMemberId));
        Set<String> memberIds = listMap.keySet();

        if (memberIds .size() > 0 ) {
            fundPayMemberWriteDao.deleteByFundPayIdAndIdCard(customFundPayId,memberIds);
        }

        fundPayFamilyWriteDao.deleteByFundPayIds(Arrays.asList(customFundPayId.split(",")));


        List<FundPayMemberEntity> rollMemberLastDb = fundPayMemberReadService.getByFundPayId(customFundPayId);

        List<FundPayMemberEntity> memberList = fundPayFamilyWriteService.partMemberInfo(canAddMemberList, excelMemberMap, customFundPayId, customFundPayDTO);

        canAddMemberList.addAll(rollMemberLastDb);

        Integer familyNum = 0;

        if (canAddMemberList.size() > 0) {

            Map<String, List<FundPayMemberEntity>> diffMemberMap = canAddMemberList.stream().collect(Collectors.groupingBy(FundPayMemberEntity::getFamilyId));
            Set<String> familyIds = diffMemberMap.keySet();
            familyNum = familyIds.size();
            List<FundPayFamilyEntity> results = new ArrayList<>();
            for (String familyId : familyIds) {
                List<FundPayMemberEntity> sameFamilyMember = diffMemberMap.get(familyId);
                Double sumFundNumber = sameFamilyMember.stream().mapToDouble(FundPayMemberEntity::getFundNumber).sum();
                FundPayFamilyEntity familyDTO = new FundPayFamilyEntity ();
                familyDTO.setId(Constant.getUUID());
                familyDTO.setFundPayId(customFundPayId);
                familyDTO.setOrderId(sameFamilyMember.get(0).getOrderId());
                familyDTO.setFamilyId(sameFamilyMember.get(0).getFamilyId());
                familyDTO.setMemberId(sameFamilyMember.get(0).getMasterMemberId());
                familyDTO.setAreaCode(sameFamilyMember.get(0).getAreaCode());
                familyDTO.setPersonNumber(sameFamilyMember.size());
                familyDTO.setPayDate(customFundPayDTO.getPayDate());
                familyDTO.setCreateTime(new Date());
                familyDTO.setFundNumber(sumFundNumber);
                familyDTO.setRemark(sameFamilyMember.get(0).getRemark());
                results.add(familyDTO);

                for (FundPayMemberEntity member : memberList) {
                    if (member.getFamilyId().equals(familyId)) {
                        member.setFundPayFamilyId(familyDTO.getId());
                    }
                }
            }

            List<List<FundPayFamilyEntity>> subFamilyList =  Lists.partition(results,1024);
            for (List<FundPayFamilyEntity> sub : subFamilyList) {
                int num = fundPayFamilyWriteDao.inserts(sub);
                if (num <= 0) {
                    throw new BizException("-1", "名册家庭信息添加失败,数据库操作异常");
                }
            }

            canAddMemberList.removeAll(rollMemberLastDb);
            List<List<FundPayMemberEntity>> subMemberList =  Lists.partition(canAddMemberList,1024);
            for (List<FundPayMemberEntity> sub : subMemberList) {
                int rst = fundPayFamilyWriteService.insertRollMembers(sub);
                if (rst <= 0) {
                    throw new BizException("-1", "成员添加失败,数据库操作异常");
                }
            }

        }

        fundPayFamilyWriteService.updateAddMemberNum(customFundPayId, canAddMemberList.size() + rollMemberLastDb.size(), familyNum);

        return packageRstMsg(excelMemberMap, canAddMemberList);
    }


    private String packageRstMsg(Map<String, FundPayMemberEntity> allExcelMemberMap, List<FundPayMemberEntity> addSuccessMemberList) {
        if (allExcelMemberMap.size() == addSuccessMemberList.size()) {

            return "导入成功";
        }
        List<String> addSuccessIdcardList = addSuccessMemberList.stream().map(FundPayMemberEntity::getIdcard).collect(Collectors.toList());
        StringBuffer rstNames = new StringBuffer("导入成功，其中【");
        for (String idcard : allExcelMemberMap.keySet()) {

            if (addSuccessIdcardList.contains(idcard) == false) {
                rstNames.append(allExcelMemberMap.get(idcard).getName()).append("、");
            }
        }
        rstNames.deleteCharAt(rstNames.length() - 1).append("】用户信息未找到");
        return rstNames.toString();
    }



    public void delAllowanceRollFamilyAndMemberInfo(String fundPayId, List<String> familyIdList) {

        fundPayMemberWriteDao.deleteByFundPayIdAndFamilyId(fundPayId, familyIdList);


        fundPayFamilyWriteService.deleteByFundPayIdAndFamilyId(fundPayId, familyIdList);


        fundPayFamilyWriteService.updateFamilyNumAndFundNumber(fundPayId, null);
    }


    public void addAllowanceFundPayFamily(FundPayEntity fundPayEntity, List<String> orderIdList, List<String> familyIds) {

        List<FundPayMemberEntity> fundPayMemberList = fundPayMemberReadService.getAddAllowanceMemberByOrderIdsAndFamilyIds(orderIdList, familyIds);


        List<FundPayFamilyEntity> fundPayFamilyList = fundPayFamilyReadService.getFamilyByAddAllowanceMember(fundPayEntity.getId(), orderIdList, familyIds, fundPayEntity.getBusinessType());


        List<String> insertFamilyIdList = fundPayFamilyList.stream().map(FundPayFamilyEntity::getFamilyId).collect(Collectors.toList());


        List<String> updateFamilyIdList = familyIds.stream().filter(familyId->!insertFamilyIdList.contains(familyId)).collect(Collectors.toList());


        AllowanceFundPayDTO allowanceFundPayDTO = new AllowanceFundPayDTO();
        BeanUtils.copyProperties(fundPayEntity, allowanceFundPayDTO);


        fundPayFamilyWriteService.calcGrantStandardByMember(fundPayFamilyList, fundPayMemberList, allowanceFundPayDTO);


        fundPayFamilyWriteService.insertFamilyMember(fundPayFamilyList, fundPayMemberList);


        fundPayFamilyWriteService.updateFamilyNumAndFundNumber(fundPayEntity.getId(), updateFamilyIdList);
    }


    public void updateFundsMember(String memberId, String changeData) {
        FundPayMemberEntity obj = new FundPayMemberEntity();
        obj.setId(memberId);
        BigDecimal fundNumber = new BigDecimal(changeData);
        obj.setFundNumber(fundNumber.doubleValue());
        fundPayMemberWriteDao.updateIgnoreNull(obj);
    }

    public List<Map<String,String>> verifyCareStand(String areaCode) {
        return fundPayMemberWriteDao.selectCareStand(areaCode);
    }
}
